package com.htdata.iiot.api.provide;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.htdata.iiot.api.service.DNService;
import com.htdata.iiot.api.tsdb.QueryTSDB;
import com.htdata.iiot.api.tsdb.bean.DataPoint;

/**
 * Created by SunMy on 2017/7/14.
 */
@RestController
@RequestMapping(value = "/tsdb")
public class RealTimeDataServiceImpl {

	public QueryTSDB queryTSDB = new QueryTSDB();
	DNService service = new DNService();
	private Logger logger = LogManager.getLogger(RealTimeDataServiceImpl.class);

	/**
	 *
	 * @param metric
	 * @param startTime
	 * @param endTime
	 * @param downsample
	 * @return
	 * @throws Exception
	 */

	public Map<String, DataPoint[]> getHistoryData(String metric, String startTime, String endTime, String downsample,
			int size) throws Exception {

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Map<String, DataPoint[]> result = new HashMap<String, DataPoint[]>();
		if (!"".equals(metric) && metric != null) {
			String[] metricNames = metric.split(",");
			if (metricNames != null && !"".equals(startTime) && startTime != null && !"".equals(endTime)
					&& endTime != null) {
				for (int i = 0; i < metricNames.length; i++) {
					String metricName = metricNames[i];
					
					Date startDate = sdf.parse(startTime);
					Date endDate = sdf.parse(endTime);
					
					DataPoint[] dPoint = new DataPoint[size];
					try {
						DataPoint[] dataPoint = null;
						dataPoint = queryTSDB.getTSData(metricName, startDate, endDate, downsample);
						logger.info(metricName + " searched result Size: " + dataPoint.length + " in time :" + startTime
								+ " ~ " + endTime + " ds:" + downsample);
						dPoint = dataPoint;
					} catch (Exception e) {
						e.printStackTrace();
					}
					result.put(metricName, dPoint);
				}

			}
		}

		return result;
	}

	@RequestMapping(value = "/getHistoryData", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
	public String getHistoryDataRest(@RequestParam("metric") String metric, @RequestParam("start") String startTime,
			@RequestParam("end") String endTime, @RequestParam("ds") String downsample) {

		logger.info("search history datapoint,its params are  metric: " + metric + " start: " + startTime + " end:"
				+ endTime + " ds:" + downsample);
		Map<String, DataPoint[]> historyData = new HashMap<String, DataPoint[]>();
		int code = 0;
		String message = null;
		try {
			historyData = getHistoryData(metric, startTime, endTime, downsample, 0);

		} catch (Exception e) {
			logger.error(e);
			e.printStackTrace();
			message = e.getMessage();
			code = 1;
		}

		return buildResult(code, historyData, message);
	}

	@RequestMapping(value = "/rel", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
	public String getRelDataRest(@RequestParam("compid") String componentIds, @RequestParam("metric") String metrics,
			@RequestParam(name = "size", defaultValue = "1", required = false) int size) {

		Map<String, DataPoint[]> relData = new HashMap<String, DataPoint[]>();
		int code = 0;
		String message = null;
		try {
			relData = getRelData(componentIds, metrics, size);
		} catch (Exception e) {
			logger.error(e);
			e.printStackTrace();
			message = e.getMessage();
			code = 1;
		}

		return buildResult(code, relData, message);
	}

	public Map<String, DataPoint[]> getRelData(String componentIds, String metrics, int size) throws Exception {

		logger.info("search rel datapoint,its params are  metric: " + metrics);
		Map<String, DataPoint[]> relData = new HashMap<String, DataPoint[]>();
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
		String startTime = sdf.format(new Date());
		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String endTime = sdf2.format(new Date());
		String[] comonentIds = componentIds.split(",");
		String[] metricsNames = metrics.split(",");
		StringBuffer resultBuffer = new StringBuffer();
		Map<String, String> componentIdAndDeviceIdMap = service.getDeviceIdsByComponentIds(componentIds);

		if (componentIdAndDeviceIdMap != null && componentIdAndDeviceIdMap.size() != 0) {
			for (int i = 0; i < comonentIds.length || i < metricsNames.length; i++) {
				String deviceNumber = componentIdAndDeviceIdMap.get(comonentIds[i]);
				if (i > 0) {
					resultBuffer.append(",");
				}
				resultBuffer.append(deviceNumber + "_" + metricsNames[i]);
			}

			relData = getHistoryData(resultBuffer.toString(), startTime, endTime, "1d-last-none", size);
		}

		return relData;
	}

	@RequestMapping(value = "/exportHistorydataToCSV/m/{metricName}/st/{startTime}/et/{endTime}/ds/{downsample}/f/{fileName}", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
	public void exportHistorydataToCSV(@PathVariable("metricName") String metric,
			@PathVariable("startTime") String startTime, @PathVariable("endTime") String endTime,
			@PathVariable("downsample") String downsample, @PathVariable("fileName") String fileName,
			HttpServletResponse response) {
		Map<String, DataPoint[]> result = new HashMap<String, DataPoint[]>();
		try {
			result = getHistoryData(metric, startTime, endTime, downsample, 0);
			logger.info("export Data : " + result.size());
		} catch (Exception e) {
			logger.error(e);
		}
		int pagesize = 100;
		String lineSeparator = System.getProperty("line.separator");
		Set<Entry<String, DataPoint[]>> entrySet = result.entrySet();
		BufferedOutputStream buff = null;
		ServletOutputStream outSTr = null;
		StringBuffer sb = new StringBuffer();
		try {
			
			response.setCharacterEncoding("UTF-8");
			// 纯下载方式
			response.setContentType("application/octet-stream");
			response.setHeader("Cache-Control", "no-cache");
			response.setHeader("Content-Disposition",
					"attachment;filename=" + new String(fileName.getBytes("gbk"), "iso-8859-1"));

			
			
			outSTr = response.getOutputStream();
			buff = new BufferedOutputStream(outSTr);
			// 文件的头文件
			String head = "dn,ts,tenantid,metricid,deviceid,metric,value" + lineSeparator;
			int index = 0;
			int pageindex = 0;
			sb.append(head);

			for (Entry<String, DataPoint[]> entry : entrySet) {
				DataPoint[] datapoints = entry.getValue();
				for (DataPoint dp : datapoints) {
					index++;
					String dn = dp.getDeviceNumber().toBase64String();
					sb.append(dn + ",");
					String ts = String.valueOf(dp.getTs());
					sb.append(ts + ",");
					Map<String, String> tags = dp.getTags();
					if (!tags.isEmpty()) {
						String tenantid = String.valueOf(tags.get("tenantid"));
						sb.append(tenantid + ",");
						String metricid = String.valueOf(tags.get("metricid"));
						sb.append(metricid + ",");
						String deviceid = String.valueOf(tags.get("deviceid"));
						sb.append(deviceid + ",");
					}
					String metricName = dp.getMetric().getName();
					sb.append(metricName + ",");
					String value = String.valueOf(dp.getMetric().getValue());
					sb.append(value);
					sb.append(lineSeparator);
					if (index % pagesize == 0 && index != 0) {
						pageindex++;
						String separator = "*************************************第" + pageindex
								+ "页***********************************" + lineSeparator;
						sb.append(separator);
					}
				}

			}

			buff.write(sb.toString().getBytes("UTF-8"));
			buff.flush();
			// 设置response的编码方式
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				buff.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				outSTr.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	private String buildResult(int code, final Map<String, DataPoint[]> result, String message) {
		ObjectMapper mapper = new ObjectMapper();
		StringWriter writer = new StringWriter();
		try {
			JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(writer);
			jsonGenerator.writeStartObject();
			jsonGenerator.writeNumberField("code", code);
			if (message != null) {
				jsonGenerator.writeStringField("message", message);
			}
			jsonGenerator.writeObjectFieldStart("data");
			for (Map.Entry<String, DataPoint[]> entry : result.entrySet()) {
				String metricName = entry.getKey();
				jsonGenerator.writeArrayFieldStart(metricName);
				DataPoint[] datapoints = entry.getValue();
				for (DataPoint dp : datapoints) {
					jsonGenerator.writeObject(dp);
				}
				jsonGenerator.writeEndArray();
			}

			jsonGenerator.writeEndObject();
			jsonGenerator.flush();
			jsonGenerator.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return writer.toString();
	}
}
